"use strict";

// 判断变量否为function
const isFunction = variable => typeof variable === 'function'


// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class MyPromise {
  constructor(handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
    //添加状态
    this._status = PENDING;
    //添加值
    this._value = undefined;
    //执行handle

    //添加成功回调函数队列
    this._fulfilledQueues = [];
    //添加失败回调函数队列
    this._rejectedQueues = [];
    try {
      handle(this._resolve.bind(this), this._reject.bind(this));
    } catch (err) {
      this._reject(err);
    }
  }

  //resolve执行的函数
  _resolve(val) {
    // this._status = FULFILLED;
    // this._value =
    const run = () =>{
      if (this._status !== PENDING) return;
      const runFulfilled = (value) =>{
        let cb;
        while(cb = this._fulfilledQueues.shift()){
          cb(val);
        }
      }
      //依次执行失败队列中的函数，并清空队列
      const runRejected = (error)=>{
        let cb;
        while(cb = this._rejectedQueues.shift()){
          cb(val);
        }
      };

      /**
       * 如果resolve的参数为Promise对象，则必须等待该Promise对象状态改变后
       * 当前Promise的状态才会改变，切状态取决于参数Promise对象的状态
       */

      if(val instanceof MyPromise){
        val.then(value=>{
          this._value = value;
          this._status = FULFILLED
          runFulfilled(value);
        }, err=>{
          this._value = err;
          this._status = REJECTED
          runRejected(err)
        })
      }else{
        this._vaule = val;
        this._status = FULFILLED
        runFulfilled(val)
      }
    };
    //为了支持同步的promise，采用异步调用
    setTimeout(run, 0)
  }

  //reject执行的函数
  _reject(err) {
    if (this._status !== PENDING) return;
    const run = () => {
      this._status = REJECTED;
      this._value = err;
      let cb;
      while (cb = this._rejectedQueues.shift()) {
        cb(err);
      }
    }
      //为了支持同步的promise 采用异步调用
      setTimeout(run, 0)

  }

  //then方法
  then(onFulfilled, onRejected){
    const {_value, _status } = this;
    //返回一个新的promise对象
    return new MyPromise((onFulfilledNext, onRejectedNext)=>{
      //封装一个成功时执行的函数
      let fulfilled = value => {
        try{
          if(!isFunction(onFulfilled)){
            onFulfilledNext(value);
          }else{
            let res = onFulfilled(value);
            if(res instanceof MyPromise){
              //如果当前回调函数返回myPromise对象，必须等待其状态改变后在执行下一个回调
              res.then(onFulfilledNext, onRejectedNext)
            }else{
              //否则会将返回结果直接作为参数，传入下一个then的回调函数，并立即执行下一个then的回调函数
              onFulfilledNext(res);
            }
          }
        }catch(err){
          //如果函数执行出错，新的Promise对象的状态为失效
          onRejectedNext(err);
        }
      };

      //封装一个失败时执行的函数
      let rejected = error =>{
        try{
          if(!isFunction(onRejected)){
            onRejectedNext(error);
          }else{
            let res = onRejected(error);
            if(res instanceof MyPromise){
              //如果当前回调函数返回MyPromise对象，必须等待其状态改变后再执行下一个回调
              res.then(onFulfilledNext, onRejectedNext)
            }else{
              //否则会将返回的结果直接作为参数，传入下一个then的回调函数，并立即执行下一个then的回调函数
              onFulfilledNext(res);
            }
          }
        }catch(err){
          //如果函数执行出错，新的Promise对象的状态为失效
          onRejectedNext(err);
        }
      };
      switch(_status){
        //当状态为pending时，把then方法回调函数加入执行队列等待执行
        case PENDING:
          this._fulfilledQueues.push(onFulfilled);
          this._rejectedQueues.push(onRejected);
          break;
        //当状态已经改变时，立即执行对应的回调函数
        case FULFILLED:
          onFulfilled(_value);
          break;
        case REJECTED:
          onRejected(_value);
          break;
      }
    })
  }

    //添加catch方法
    catch(onRejected){
       return this.then(undefined, onRejected);
    }

  //添加静态resolve方法
    static  resolve(value){
    //如果参数是MyPromise实例，直接返回这个实例
      if(value instanceof MyPromise) return value;
      return new MyPromise(resolve => resolve(value))
  }

  //添加reject方法
  static reject(value){
    return new MyPromise((resolve, reject)=>reject(value));
  }

  //添加静态all方法
  static all(list){
    return new MyPromise((resolve, reject)=>{
      /**
       * 返回值集合
       */
      let values = [];
      let count =0;
      for(let [i,p] of list.entries){
        //数组参数如果不是MyPromise实例， 先调用MyPromise.resolve
        this.resolve(p).then(res=>{
          values[i] = res;
          count++
          //所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
          if(count === list.length) resolve(values);
        }, err =>{
          //有一个被rejected时返回的MyPromise状态就变成rejected
          reject(err);
        })
      }
    })
  }

  //race 方法
  //添加race静态方法
  static race(list){
    return new MyPromise((resolve, reject)=>{
      for(let p of list){
        //只要有一个实例先改变状态，新的MyPromise的状态就跟着改变
        this.resolve(p).then(res=>{
          resolve(res);
        }, err=>{
          reject(err)
        })
      }
    })
  }

  //finally
  finally(cb){
    return this.then(
      value => MyPromise.resolve(cb()).then(()=>value),
      reason=>MyPromise.resolve(cb()).then(()=>throw reason)
    )
  }
}
